﻿using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
using System;

public class ABPackVersionUpdate : MonoBehaviour
    {
        /// <summary> AB包存放路径，方便修改。/*streamingAssets文件夹在PC端是可读可写的*/ </summary>
        public static string ABPathUrl => Application.streamingAssetsPath + "/";  /* 假设是该路径 */
        /// <summary> AB下载路径，方便修改 </summary>
        public static string ABWebUrl => "D:/AssetBundles/PC/";
        /// <summary> 主包名，方便修改 </summary>
        public static string ABMainName
        {
            get
            {
#if UNITY_IOS
			return "IOS";
#elif UNITY_ANDROID
			return "Andriod";
#else
                return "PC";
#endif
            }
        }

        //  需要下载的文件list
        List<string> downloadList;

        //  *** 进度显示 *** //
        /// <summary> 当前下载任务是否完成，只能同时开启一个下载任务 </summary>
        private bool IsLoad = false;
        /// <summary> 单条任务下载进度(网址，进度) </summary>
        public Action<string, float> OnSingleTaskPercent;
        public Action<string> OnAllTaskDetail;

        private void Awake()
        {
            downloadList = new List<string>();
        }

        private void Start()
        {
            //  判断StreamingAssets文件夹是否存在
            if (!Directory.Exists(Application.streamingAssetsPath))
            {
                Directory.CreateDirectory(Application.streamingAssetsPath);
            }

            // 判断主包是否存在
            if (!File.Exists(ABPathUrl + ABMainName))
            {
                Debug.Log("初次下载资源...");
                StartCoroutine(DownloadAllABFromWeb(ABWebUrl, ABPathUrl));
            }
            else
            {
                Debug.Log("更新资源...");
                StartCoroutine(CompareAndUpdateAllABFromWeb(ABWebUrl, ABPathUrl));
            }
        }

        /// <summary>
        /// 从web下载所有ab包
        /// </summary>
        /// <param name="url">下载路径</param>
        /// <param name="path">存放路径</param>
        /// <returns></returns>
        IEnumerator DownloadAllABFromWeb(string url, string path)
        {
            UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(url + ABMainName);
            yield return request.SendWebRequest();

            // 获取主包
            AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
            // 获取manifest文件
            // 固定name
            AssetBundleManifest manifest = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
            // 将总包下载到本地
            // 下载路径+name，存放路径+name
            StartCoroutine(DownloadABToLocal(url + ABMainName, path + ABMainName));
            yield return new WaitUntil(() => IsLoad == false);
            //  遍历所有子ab包
            int i = 1;
            foreach (var name in manifest.GetAllAssetBundles())
            {
                OnAllTaskDetail?.Invoke("总任务：" + manifest.GetAllAssetBundles().Length.ToString() + "当前任务：" + i.ToString());
                StartCoroutine(DownloadABToLocal(url + name, path + name));
                i++;
                yield return new WaitUntil(() => IsLoad == false);
            }
            //  卸载主包
            ab.Unload(true);
            Debug.Log("资源下载结束...");
        }

        /// <summary>
        /// 下载单个ab包
        /// </summary>
        /// <param name="url"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        IEnumerator DownloadABToLocal(string url, string path)
        {
            #region 原来的，多条任务
            //UnityWebRequest request = UnityWebRequest.Get(url);
            //yield return request.SendWebRequest();
            ////  将文件写入本地
            //FileStream fs = new FileStream(path, FileMode.Create);
            //fs.Write(request.downloadHandler.data, 0, request.downloadHandler.data.Length);
            //fs.Close();

            //Debug.Log("已下载 " + path);

            //request = UnityWebRequest.Get(url + ".manifest");
            //yield return request.SendWebRequest();
            ////  将manifest文件也写入本地
            //fs = new FileStream(path + ".manifest", FileMode.Create);
            //fs.Write(request.downloadHandler.data, 0, request.downloadHandler.data.Length);
            //fs.Close();

            //Debug.Log("已下载 " + path + ".manifest");
            #endregion

            IsLoad = true;// 正在下载
            UnityWebRequest request = UnityWebRequest.Get(url);
            request.SendWebRequest();
            // 显示进度
            OnSingleTaskPercent?.Invoke(url, 0);
            while (!request.isDone)
            {
                if (request.result == UnityWebRequest.Result.ProtocolError ||
                    request.result == UnityWebRequest.Result.ConnectionError)
                {                   
                    Debug.LogError("当前的下载发生错误：" + request.error);
                    IsLoad = false;
                    yield break;
                }
                //Debug.Log("当前的下载进度为：" + request.downloadProgress);
                OnSingleTaskPercent?.Invoke(url, request.downloadProgress);
                yield return null;
            }
            //  将文件写入本地
            FileStream fs = new FileStream(path, FileMode.Create);
            fs.Write(request.downloadHandler.data, 0, request.downloadHandler.data.Length);
            fs.Close();

            Debug.Log("已下载 " + path);


            request = UnityWebRequest.Get(url + ".manifest");
            request.SendWebRequest();
            // 显示进度
            OnSingleTaskPercent?.Invoke(url, 0);
            while (!request.isDone)
            {
                if (request.result == UnityWebRequest.Result.ProtocolError ||
                    request.result == UnityWebRequest.Result.ConnectionError)
                {
                    Debug.LogError("当前的下载发生错误" + request.error);
                    IsLoad = false;
                    yield break;
                }
                //Debug.Log("当前的下载进度为：" + request.downloadProgress);
                OnSingleTaskPercent?.Invoke(url, request.downloadProgress);
                yield return null;
            }
            //  将manifest文件也写入本地
            fs = new FileStream(path + ".manifest", FileMode.Create);
            fs.Write(request.downloadHandler.data, 0, request.downloadHandler.data.Length);
            fs.Close();

            IsLoad = false;// 下载完成
            Debug.Log("已下载 " + path + ".manifest");
        }

        /// <summary>
        /// 从web更新ab包
        /// </summary>
        /// <param name="url">下载路径</param>
        /// <param name="path">存放路径</param>
        /// <returns></returns>
        IEnumerator CompareAndUpdateAllABFromWeb(string url, string path)
        {
            //  网络资源哈希
            Dictionary<string, Hash128> netDic = new Dictionary<string, Hash128>();
            //  本地资源哈希
            Dictionary<string, Hash128> localDic = new Dictionary<string, Hash128>();

            // ****  获取网络上ab包信息 ***** //
            //  获取网络资源
            UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(url + ABMainName);
            yield return request.SendWebRequest();
            // 获取web的主包
            AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
            AssetBundleManifest manifest = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
            foreach (var name in manifest.GetAllAssetBundles())
            {
                //  存储网络资源哈希
                netDic.Add(name, manifest.GetAssetBundleHash(name));
            }
            ab.Unload(true);

            // ****  获取本地ab包信息 ***** //
            //  获取本地资源
            request = UnityWebRequestAssetBundle.GetAssetBundle(path + ABMainName);
            yield return request.SendWebRequest();

            ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
            manifest = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
            foreach (var name in manifest.GetAllAssetBundles())
            {
                //  存储本地资源哈希
                localDic.Add(name, manifest.GetAssetBundleHash(name));
            }
            ab.Unload(true);

            // ****  遍历比较，获取需要更新下载的包name ***** //
            //  遍历网络资源
            foreach (var item in netDic)
            {
                Debug.Log("校验资源：" + item);
                //  本地不包含当前key 是新增资源
                if (!localDic.ContainsKey(item.Key))
                {
                    downloadList.Add(item.Key);
                }
                //  包含的话判断哈希是否相同
                else
                {
                    //  不相同则更新资源
                    if (!localDic[item.Key].Equals(item.Value))
                    {
                        downloadList.Add(item.Key);
                    }
                }
            }

            // ****  获取需要更新下载的包 ***** //
            //  如果有需要更新的资源
            if (downloadList.Count > 0)
            {
                //  总包也需要更新
                downloadList.Add("AssetBundle");
                int i = 1;
                foreach (var name in downloadList)
                {
                    OnAllTaskDetail?.Invoke("总任务：" + manifest.GetAllAssetBundles().Length.ToString() + "当前任务：" + i.ToString());
                    StartCoroutine(DownloadABToLocal(url + name, path + name));
                    i++;
                    yield return new WaitUntil(() => IsLoad == false);
                }
                Debug.Log("更新资源结束...");
            }
            else
            {
                Debug.Log("无更新...");
            }
        }
    }